import { useCallback, useEffect, useMemo } from 'react';
import { toast } from 'react-toastify';
import { Fetcher, SWRConfiguration } from 'swr';
import useSWRImmutable from 'swr/immutable';

import { getApiErrorMessage } from '@donnu-prod-practice/api';

export const useImmutableQuery = <ReturnDataType, ResponseType>(
  key: string,
  fetcher: Fetcher<ResponseType>,
  transformer: (res: ResponseType) => ReturnDataType,
  notification: {
    readonly loading?: string;
    readonly got?: string;
    readonly updated?: string;
    readonly error?: string;
  } = {},
  config: SWRConfiguration<ResponseType> = {}
) => {
  const { data, error, isValidating, mutate } = useSWRImmutable<ResponseType>(key, fetcher, config);

  /* -------------------------------------------------------------------------- */

  const errorIsExist = useMemo(() => !!error, [error]);

  const errorMessage = useMemo(() => (errorIsExist ? getApiErrorMessage(error) : null), [error, errorIsExist]);

  useEffect(() => {
    if (errorIsExist && !!errorMessage && !!notification.error) toast.error(`${notification.error}: ${errorMessage}`);
  }, [errorIsExist, errorMessage, notification.error]);

  /* -------------------------------------------------------------------------- */

  const returnedData = useMemo(() => (data !== undefined ? transformer(data) : null), [data, transformer]);

  /* -------------------------------------------------------------------------- */

  const isLoading = useMemo(() => !errorIsExist && !returnedData, [errorIsExist, returnedData]);

  /* -------------------------------------------------------------------------- */

  const refresh = useCallback(() => mutate(), [mutate]);

  /* -------------------------------------------------------------------------- */

  useEffect(() => {
    if (isLoading && !!notification.loading) toast.info(notification.loading);
  }, [isLoading, notification.loading]);

  /* -------------------------------------------------------------------------- */

  const isLoaded = useMemo(() => !!returnedData, [returnedData]);

  const JSONData = useMemo(() => (!!returnedData ? JSON.stringify(returnedData) : null), [returnedData]);

  useEffect(() => {
    if (isLoaded && !!JSONData) {
      if (isValidating) {
        if (!!notification.updated) toast.info(notification.updated);
      } else if (!!notification.got) toast.info(notification.got);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [notification.updated, JSONData, isLoaded, notification.got]);

  /* -------------------------------------------------------------------------- */

  return {
    data: returnedData,
    error: errorMessage,
    isLoading,
    refresh,
    mutate,
  };
};
